package com.example.socket.core;

import java.util.ArrayList;
import java.util.List;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * 通信信息对象
 *
 * <pre>
 * 包：信息头+通信信息
 *
 * 信息头:[长度][会话][序号][状态][模块号][指令]
 * 信息体:[内容]
 * </pre>
 */
public class Message {

    private static final Logger logger = LoggerFactory.getLogger(Message.class);

    /** 信息头 */
    private Header header;
    /** 信息体 */
    private byte[] body = new byte[0];
    /** 是否忽略消息 */
    private transient boolean ignore;

    /** 从原始包数据构建信息对象实例 */
    public static Message valueOf(ByteBuf buff) {
        try {
            Message result = new Message();
            // 头长度
            buff.readInt();
            result.header = Header.valueOf(buff);
            int size = buff.readableBytes();
            if (size > 0) {
                result.body = new byte[size];
                buff.readBytes(result.body);
            }
            return result;
        } catch (Exception e) {
            String message = "创建通信信息对象异常";
            logger.error(message, e);
            throw new RuntimeException(message, e);
        }
    }

    public static List<Message> valuesOf(ByteBuf buff) {
        List<Message> result = new ArrayList<Message>();
        while (buff.readableBytes() != 0) {
            short length = buff.readShort();
            Message message = new Message();
            message.header = Header.valueOf(buff);
            int bodySize = length - message.header.getSize();
            message.body = new byte[bodySize];
            buff.readBytes(message.body);
            result.add(message);
        }
        return result;
    }

    public static Message valueOf(Header header, byte[] body) {
        Message result = new Message();
        result.header = header;
        if (body != null) {
            result.body = body;
        }
        return result;
    }

    /**
     * 将对象转换为 byte[]
     */
    public byte[] toBytes() {
        int msgLen = header.getSize() + (body == null ? 0 : body.length);
        ByteBuf buffer = Unpooled.buffer(msgLen);
        write(buffer, msgLen);
        byte[] result = new byte[msgLen];
        buffer.readBytes(result);
        buffer.release();
        return result;
    }

    /**
     * 将对象写入输出流
     */
    public void write(ByteBuf out, int length) {
        byte[] headerBytes = header.toBytes(length);
        out.writeBytes(headerBytes);
        if (body != null) {
            out.writeBytes(body);
        }
    }

    public Message copy() {
        return Message.valueOf(header.copy(), body);
    }

    /**
     * 清空消息体
     * @return 对象自身
     */
    public Message clearBody() {
        this.body = new byte[0];
        return this;
    }

    /**
     * 将状态重置为正常{@link Response}的状态
     * @return 对象自身
     */
    public Message changeToNormalResponse() {
        header.setState(MessageConstant.STATE_RESPONSE);
        return this;
    }

    /**
     * 将状态重置为错误{@link Response}的状态
     * @param state 错误状态值
     * @return 对象自身
     */
    public Message changeToErrorResponse(short state) {
        header.setState((short) (MessageConstant.STATE_ERROR + MessageConstant.STATE_RESPONSE + state));
        return this;
    }

    /**
     * 检查是否有指定状态
     * @param checked 状态标识
     * @return
     */
    public boolean hasState(short checked) {
        return header.hasState(checked);
    }

    /**
     * 添加状态
     * @param added 被添加的状态
     */
    public void addState(short added) {
        header.addState(added);
    }

    /**
     * 移除状态
     * @param removed 被移除的状态
     */
    public void removeState(short removed) {
        header.removeState(removed);
    }

    @Override
    public String toString() {
        return "H:=" + header + " B:" + (body == null ? 0 : body.length);
    }

    // Getter and Setter ...

    @JsonIgnore
    public Command getCommand() {
        return header.getCommand();
    }

    @JsonIgnore
    public boolean isResponse() {
        return header.isResponse();
    }

    @JsonIgnore
    public short getState() {
        return header.getState();
    }

    @JsonIgnore
    public int getSn() {
        return header.getSn();
    }

    public void setSn(int sn) {
        header.setSn(sn);
    }

    public byte[] getBody() {
        return body;
    }

    public void setBody(byte[] body) {
        this.body = body;
    }

    @JsonIgnore
    public boolean isIgnore() {
        return ignore;
    }

    public void setIgnore(boolean ignore) {
        this.ignore = ignore;
    }

    @JsonIgnore
    public long getSession() {
        return header.getSession();
    }

    public void setSession(long session) {
        header.setSession(session);
    }

    public Header getHeader() {
        return header;
    }

    public void setHeader(Header header) {
        this.header = header;
    }

    /**
     * 将对象转换为 ByteBuf
     * 零拷贝
     */
    public ByteBuf toBuffer(CompositeByteBuf buffer, ByteBufAllocator alloc) {
        int msgLen = header.getSize() + (body == null ? 0 : body.length);
        //消息头
        ByteBuf headerBuff = header.toBytes(alloc, msgLen);
        buffer.addComponent(true, headerBuff);
        if (body != null) {
            buffer.addComponent(true, Unpooled.wrappedBuffer(body));
        }
        return buffer;
    }
}